package com.abo.yaas.webservice.utils;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import com.abo.yaas.domain.User;

/**
 * Utility class containing useful helper methods related to passwords.
 */
@SuppressWarnings("serial")
public class PasswordUtil implements Serializable {
    // Store the password salt in a static variable
    private static String salt = null;

    /**
     * Generates a hashed password of the given string.
     * 
     * @param password
     *            String which is to be hashed
     * @return Hashed password
     */
    public static String generateHashedPassword(String password) {
        final StringBuffer hashedPassword = new StringBuffer();

        // Get a byte array of the password concatenated with the password salt
        // value
        final byte[] defaultBytes = (password + getSalt()).getBytes();
        try {
            // Perform the hashing with SHA
            final MessageDigest algorithm = MessageDigest.getInstance("SHA");
            algorithm.reset();
            algorithm.update(defaultBytes);
            final byte messageDigest[] = algorithm.digest();

            for (int i = 0; i < messageDigest.length; i++) {
                hashedPassword.append(Integer
                        .toHexString(0xFF & messageDigest[i]));
            }
        } catch (final NoSuchAlgorithmException nsae) {

        }

        return hashedPassword.toString();
    }

    /**
     * Returns the minimum length of a password
     * 
     * @return Minimum password length
     */
    public static int getMinPasswordLength() {
        final String minLenghtStr = System
                .getProperty("authentication.password.validation.length");
        int minLenght = 8;
        if (minLenghtStr == null) {
            System.setProperty("authentication.password.validation.length", "8");
            return minLenght;
        }

        try {
            minLenght = Integer.valueOf(minLenghtStr);
        } catch (final NumberFormatException e) {
            throw new IllegalArgumentException(
                    "authentication.password.validation.length must be an integer");
        }

        return minLenght;
    }

    /**
     * Get the salt value for the passwords
     * 
     * @return
     */
    protected static String getSalt() {
        // Check if the salt has been set. If not, then create a default salt
        // value.
        final String systemSalt = System
                .getProperty("authentication.password.salt");
        if (salt != null && !salt.equals(systemSalt)) {
            throw new UnsupportedOperationException(
                    "Password salt is already set");
        }

        if (salt == null && systemSalt != null) {
            salt = systemSalt;
        }

        if (salt == null) {
            salt = ")%gersK43q5)=%3qiyt34389py43pqhgwer8l9";
            System.setProperty("authentication.password.salt", salt);
        }

        return salt;
    }

    /**
     * Verify if the given password (unhashed) matches with the user's password
     * 
     * @param pwd
     *            User to whome's password we are comparing
     * @param password
     *            The unhashed password we are comparing
     * @return Returns true if passwords match, otherwise false
     */
    public static boolean verifyPassword(final User user, String password) {
        // Return null if either the username or password is null
        if (user == null || password == null) {
            return false;
        }
        final String hashedPassword = generateHashedPassword(password);
        return user.getPasswordHash().equals(hashedPassword);
    }
}
